package com.dragon.backstage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dragon.backstage.constant.LoginConstant;
import com.dragon.backstage.convert.RoleConvert;
import com.dragon.backstage.convert.UserConvert;
import com.dragon.backstage.domain.param.user.UserAddParam;
import com.dragon.backstage.domain.param.user.UserAuthRoleAddBatchParam;
import com.dragon.backstage.domain.param.user.UserAuthRoleParam;
import com.dragon.backstage.domain.param.user.UserChangeStatusParam;
import com.dragon.backstage.domain.param.user.UserEditParam;
import com.dragon.backstage.domain.param.user.UserParam;
import com.dragon.backstage.domain.vo.user.UserAuthRoleVo;
import com.dragon.backstage.domain.vo.user.UserDetailVo;
import com.dragon.backstage.domain.vo.user.UserVo;
import com.dragon.backstage.service.UserRoleService;
import com.dragon.backstage.service.UserService;
import com.dragon.common.core.crypto.SecureUtil;
import com.dragon.common.domain.vo.PaginationVo;
import com.dragon.common.utils.AjaxResult;
import com.dragon.common.utils.cache.RedisUtils;
import com.dragon.interfaces.constant.RoleConstant;
import com.dragon.interfaces.constant.UserConstant;
import com.dragon.interfaces.domain.request.role.RoleRequest;
import com.dragon.interfaces.domain.request.user.UserRequest;
import com.dragon.interfaces.entity.Role;
import com.dragon.interfaces.entity.User;
import com.dragon.interfaces.entity.UserRole;
import com.dragon.interfaces.mapper.RoleMapper;
import com.dragon.interfaces.mapper.UserMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragon.interfaces.mapper.UserRoleMapper;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author dragon
 * @since 2024-07-31 17:42:19
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private UserRoleService userRoleService;


    /**
     * 用户信息缓存初始化
     *
     * @param userId 用户ID
     */
    @Override
    public void userInfoCacheInit(long userId) {
        userInfoCacheInit(userId, Boolean.FALSE);
    }

    /**
     * 用户信息缓存初始化
     *
     * @param userId     用户ID
     * @param forcedInit 是否强制初始化
     */
    @Override
    public void userInfoCacheInit(long userId, boolean forcedInit) {
        String userInfoKey = String.format(LoginConstant.USER_INFO_CACHE_KEY, userId);

        boolean exists = redisUtils.exists(userInfoKey);

        if (!exists || Boolean.TRUE.equals(forcedInit)) {
            User user = this.getById(userId);
            if (!Objects.isNull(user)) {
                Map<String, String> userInfoMap = new HashMap<>(16);
                userInfoMap.put(User.USER_ID, user.getUserId().toString());
                userInfoMap.put(User.ACCOUNT, user.getAccount());
                userInfoMap.put(User.NICK_NAME, user.getNickName());
                userInfoMap.put(User.USER_TYPE, user.getUserType());
                userInfoMap.put(User.EMAIL, user.getEmail());
                userInfoMap.put(User.PHONE_NUMBER, user.getEmail());
                userInfoMap.put(User.SEX, user.getSex());
                userInfoMap.put(User.AVATAR, user.getAvatar());
                userInfoMap.put(User.STATUS, user.getStatus().toString());
                userInfoMap.put(User.LOGIN_IP, user.getLoginIp());
                userInfoMap.put(User.LOGIN_TIME, user.getLoginTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.CHINA)));
                userInfoMap.put(User.REMARK, user.getRemark());

                redisUtils.hmSet(userInfoKey, userInfoMap);
                if (!exists) {
                    // 缓存一小时
                    redisUtils.expire(userInfoKey, 3600);
                }
            }
        }
    }

    /**
     * 获取用户昵称
     *
     * @param account 账号
     * @return 用户昵称
     */
    @Override
    public String getNickNameByAccount(String account) {
        if (StringUtils.isNotBlank(account)) {
            String userNickNameKey = LoginConstant.USER_ACCOUNT_NICK_NAME_CACHE_KEY;

            boolean exists = redisUtils.exists(userNickNameKey);

            String nickName = (String) redisUtils.hGet(userNickNameKey, account);
            if (StringUtils.isBlank(nickName)) {
                User user = lambdaQuery().eq(User::getAccount, account).one();
                if (Objects.nonNull(user)) {
                    nickName = user.getNickName();

                    redisUtils.hSet(userNickNameKey, account, nickName);
                    if (!exists) {
                        // 缓存一小时
                        redisUtils.expire(userNickNameKey, 3600);
                    }
                }
            }

            return nickName;
        }

        return StringUtils.EMPTY;
    }

    /**
     * 用户列表
     *
     * @param param 请求参数
     * @return 用户列表
     */
    @Override
    public AjaxResult<PaginationVo<UserVo>> userList(UserParam param) {
        UserRequest userRequest = UserConvert.toUserRequest(param);

        List<User> userList = userMapper.selectUserList(userRequest);
        int total = userMapper.selectUserCount(userRequest);

        List<UserVo> userVos = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userList)) {
            for (User user : userList) {
                userVos.add(UserConvert.toUserVo(user));
            }
        }

        return AjaxResult.succeedWith(PaginationVo
            .<UserVo>builder()
            .total(total)
            .rows(userVos)
            .build()
        );
    }

    /**
     * 用户详情
     *
     * @param userId 用户ID
     * @return 用户详情
     */
    @Override
    public AjaxResult<UserDetailVo> userDetail(Long userId) {
        if (Objects.isNull(userId) || userId < 1L) {
            return AjaxResult.failed("用户编号不能为空");
        }

        User user = userMapper.selectById(userId);
        if (Objects.isNull(user)) {
            return AjaxResult.failed("用户不存在");
        }

        return AjaxResult.succeedWith(UserConvert.toUserDetailVo(user));
    }

    /**
     * 添加用户
     *
     * @param param 请求参数
     * @return 添加结果
     */
    @Override
    public AjaxResult<Void> addUser(UserAddParam param) {
        AjaxResult<Void> check = UserAddParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        // 判断账号是否存在
        boolean isExistAccount = userMapper.exists(new QueryWrapper<User>()
            .eq(User.ACCOUNT, param.getAccount())
        );
        if (isExistAccount) {
            return AjaxResult.failed("账号已存在");
        }

        boolean flag = userMapper.insert(User
            .builder()
            .account(param.getAccount())
            .nickName(param.getNickName())
            .userType(UserConstant.USER_TYPE_GENERAL)
            .email(param.getEmail())
            .phoneNumber(param.getPhoneNumber())
            .sex(param.getSex())
            .avatar(param.getAvatar())
            .password(SecureUtil.sha512().digestHex(param.getPassword()))
            .status(UserConstant.STATUS_NORMAL)
            .remark(param.getRemark())
            .build()
        ) > 0;
        if (!flag) {
            return AjaxResult.failed("用户添加失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 编辑用户
     *
     * @param param 请求参数
     * @return 编辑结果
     */
    @Override
    public AjaxResult<Void> editUser(UserEditParam param) {
        AjaxResult<Void> check = UserEditParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        // 判断账号是否存在
        boolean isExistAccount = userMapper.exists(new QueryWrapper<User>()
            .eq(User.ACCOUNT, param.getAccount())
            .ne(User.USER_ID, param.getUserId())
        );
        if (isExistAccount) {
            return AjaxResult.failed("账号已存在");
        }

        User user = userMapper.selectById(param.getUserId());
        if (Objects.isNull(user)) {
            return AjaxResult.failed("用户不存在");
        }
        if (UserConstant.SUPER_ADMIN_ACCOUNT.equals(user.getAccount())) {
            return AjaxResult.failed("该用户无法编辑");
        }

        User userEdit = User
            .builder()
            .userId(param.getUserId())
            .account(param.getAccount())
            .nickName(param.getNickName())
            .email(param.getEmail())
            .phoneNumber(param.getPhoneNumber())
            .sex(param.getSex())
            .avatar(param.getAvatar())
            .status(param.getStatus())
            .remark(param.getRemark())
            .build();
        if (StringUtils.isNotBlank(param.getPassword())) {
            userEdit.setPassword(SecureUtil.sha512().digestHex(param.getPassword()));
        }

        boolean flag = userMapper.updateById(userEdit) > 0;
        if (!flag) {
            return AjaxResult.failed("用户编辑失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 删除用户
     *
     * @param userId 用户ID
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<Void> deleteUser(Long userId) {
        if (Objects.isNull(userId) || userId < 1L) {
            return AjaxResult.failed("用户ID不能为空");
        }

        User user = userMapper.selectById(userId);
        if (Objects.isNull(user)) {
            return AjaxResult.failed("用户不存在");
        }
        if (UserConstant.SUPER_ADMIN_ACCOUNT.equals(user.getAccount())) {
            return AjaxResult.failed("该用户无法删除");
        }

        boolean delFlag = userMapper.deleteById(userId) > 0;
        if (!delFlag) {
            throw new RuntimeException("用户删除失败");
        }

        long userRoleNum = userRoleMapper.selectCount(new QueryWrapper<UserRole>()
            .eq(UserRole.USER_ID, userId)
        );
        if (userRoleNum > 0) {
            boolean delFlag2 = userRoleMapper.delete(new QueryWrapper<UserRole>()
                .eq(UserRole.USER_ID, userId)
            ) > 0;
            if (!delFlag2) {
                throw new RuntimeException("用户关联角色删除失败");
            }
        }

        return AjaxResult.succeed();
    }

    /**
     * 更改用户状态
     *
     * @param param 请求参数
     * @return 更改结果
     */
    @Override
    public AjaxResult<Void> changeStatus(UserChangeStatusParam param) {
        AjaxResult<Void> check = UserChangeStatusParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        User user = userMapper.selectById(param.getUserId());
        if (Objects.isNull(user)) {
            return AjaxResult.failed("用户不存在");
        }
        if (UserConstant.SUPER_ADMIN_ACCOUNT.equals(user.getAccount())) {
            return AjaxResult.failed("该用户无法切换状态");
        }

        User userEdit = User
            .builder()
            .status(param.getStatus())
            .build();

        QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .eq(User.USER_ID, param.getUserId())
            ;
        boolean flag = userMapper.update(userEdit, wrapper) > 0;
        if (!flag) {
            return AjaxResult.failed("用户状态更改失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 授权角色列表
     *
     * @param param 请求参数
     * @return 授权角色列表
     */
    @Override
    public AjaxResult<PaginationVo<UserAuthRoleVo>> authRoleList(UserAuthRoleParam param) {
        AjaxResult<Void> check = UserAuthRoleParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        RoleRequest roleRequest = RoleConvert.toRoleRequest(param);
        roleRequest.setExcludeRoleKeys(Lists.newArrayList(
            RoleConstant.SUPER_ADMIN_ROLE_KEY
        ));

        List<UserAuthRoleVo> userAuthRoleVos = new ArrayList<>();
        int total = roleMapper.selectRoleCount(roleRequest);
        List<Role> roleList = roleMapper.selectRoleList(roleRequest);

        if (CollectionUtils.isNotEmpty(roleList)) {
            // 用户拥有的角色
            List<Long> roleIds = userRoleMapper.selectRoleIdsByUserId(param.getUserId());
            for (Role role : roleList) {
                userAuthRoleVos.add(UserConvert.toUserAuthRoleVo(role, roleIds));
            }
        }

        return AjaxResult.succeedWith(PaginationVo
            .<UserAuthRoleVo>builder()
            .total(total)
            .rows(userAuthRoleVos)
            .build()
        );
    }

    /**
     * 批量添加授权角色
     *
     * @param param 请求参数
     * @return 批量添加结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<Void> addAuthRoleBatch(UserAuthRoleAddBatchParam param) {
        AjaxResult<Void> check = UserAuthRoleAddBatchParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        User user = userMapper.selectById(param.getUserId());
        if (Objects.isNull(user)) {
            return AjaxResult.failed("用户不存在");
        }
        if (UserConstant.SUPER_ADMIN_ACCOUNT.equals(user.getAccount())) {
            return AjaxResult.failed("该用户无法添加角色");
        }

        long userRoleNum = userRoleMapper.selectCount(new QueryWrapper<UserRole>()
            .eq(UserRole.USER_ID, param.getUserId())
        );
        if (userRoleNum > 0) {
            boolean flag = userRoleMapper.delete(new QueryWrapper<UserRole>()
                .eq(UserRole.USER_ID, param.getUserId())
            ) > 0;
            if (!flag) {
                throw new RuntimeException("用户角色删除失败");
            }
        }

        if (CollectionUtils.isNotEmpty(param.getRoleIds())) {
            List<UserRole> insertUserRoles = param.getRoleIds()
                .stream()
                .map(roleId -> UserRole.builder().userId(param.getUserId()).roleId(roleId).build())
                .collect(Collectors.toList());
            boolean flag2 = userRoleService.saveBatch(insertUserRoles);
            if (!flag2) {
                throw new RuntimeException("用户角色添加失败");
            }
        }

        return AjaxResult.succeed();
    }

}
